// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.io.Serializable;
// import java.util.ArrayList;
// import java.util.List;

#include "SQLContainsExpr.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/listAddAll.h"
#include "../../../utils/ifeq.h"
#include "SQLBooleanExpr.h"
#include "../SQLDataType.h"

long SQLContainsExpr::serialVersionUID = 1L;

SQLContainsExpr::SQLContainsExpr()
{
  targetList = std::make_shared<std::list<SQLExpr_ptr>>();
}

SQLContainsExpr::SQLContainsExpr(SQLExpr_ptr expr)
{
  targetList = std::make_shared<std::list<SQLExpr_ptr>>();
  this->setExpr(expr);
}

SQLContainsExpr::SQLContainsExpr(SQLExpr_ptr expr, BOOL_ptr not_)
{
  targetList = std::make_shared<std::list<SQLExpr_ptr>>();
  this->setExpr(expr);
  this->not_ = not_;
}

SQLContainsExpr::~SQLContainsExpr() {}

SQLObject_ptr SQLContainsExpr::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLContainsExpr>(new SQLContainsExpr());
  std::shared_ptr<SQLContainsExpr> x = std::dynamic_pointer_cast<SQLContainsExpr>(clone_tmp);
  // SQLContainsExpr x = new SQLContainsExpr();
  x->not_ = not_;
  if (expr != nullptr)
  {
    x->setExpr(std::dynamic_pointer_cast<SQLExpr>(expr->clone()));
  }
  for (SQLExpr_ptr e : *targetList)
  {
    SQLExpr_ptr e2 = std::dynamic_pointer_cast<SQLExpr>(e->clone());
    e2->setParent(x);
    x->targetList->push_back(e2);
  }
  return x;
}

BOOL_ptr SQLContainsExpr::isNot()
{
  return this->not_;
}

void SQLContainsExpr::setNot(BOOL_ptr not_)
{
  this->not_ = not_;
}

SQLExpr_ptr SQLContainsExpr::getExpr()
{
  return this->expr;
}

void SQLContainsExpr::setExpr(SQLExpr_ptr expr)
{
  if (expr != nullptr)
  {
    expr->setParent(SharedObject(SQLContainsExpr));
  }

  this->expr = expr;
}

SQLExpr_list_ptr SQLContainsExpr::getTargetList()
{
  return this->targetList;
}

void SQLContainsExpr::setTargetList(SQLExpr_list_ptr targetList)
{
  this->targetList = targetList;
}

void SQLContainsExpr::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLContainsExpr)))
  {
    if (this->expr != nullptr)
    {
      this->expr->accept(visitor);
    }

    if (this->targetList != nullptr)
    {
      for (SQLExpr_ptr item : *this->targetList)
      {
        if (item != nullptr)
        {
          item->accept(visitor);
        }
      }
    }
  }

  visitor->endVisit(SharedObject(SQLContainsExpr));
}

SQLObject_list_ptr SQLContainsExpr::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  if (this->expr != nullptr)
  {
    children->push_back(this->expr);
  }
  // children.addAll(this->targetList);
  Utils::ListAddAll<SQLExpr, SQLObject>(this->targetList, children);
  return children;
}

//@Override
int SQLContainsExpr::hashCode()
{
  int prime = 31;
  int result = 1;
  result = prime * result + ((expr == nullptr) ? 0 : expr->hashCode());
  result = prime * result + (not_ ? 1231 : 1237);
  // result = prime * result + ((targetList == nullptr) ? 0 : targetList->hashCode());
  result = prime * result + ((targetList == nullptr) ? 0 : targetList->size());
  return result;
}

//@Override
bool SQLContainsExpr::equals(Object_ptr obj)
{
  if (this == obj.get())
  {
    return true;
  }
  if (obj == nullptr)
  {
    return false;
  }
  if (getClass() != obj->getClass())
  {
    return false;
  }
  std::shared_ptr<SQLContainsExpr> other = std::dynamic_pointer_cast<SQLContainsExpr>(obj);
  if (expr == nullptr)
  {
    if (other->expr != nullptr)
    {
      return false;
    }
  }
  else if (!expr->equals(other->expr))
  {
    return false;
  }
  if (not_ != other->not_)
  {
    return false;
  }
  if (targetList == nullptr)
  {
    if (other->targetList != nullptr)
    {
      return false;
    }
  }
  else if (!IFEQ::ifeq<SQLExpr_ptr>(targetList, other->targetList))
  {
    return false;
  }
  return true;
}

SQLDataType_ptr SQLContainsExpr::computeDataType()
{
  return SQLBooleanExpr::DATA_TYPE;
}

//@Override
BOOL_ptr SQLContainsExpr::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (this->expr == expr)
  {
    setExpr(target);
    return BOOL::TRUE;
  }

  auto it_targetList = targetList->begin();
  for (int i = 0; i < targetList->size(); i++)
  {
    std::advance(it_targetList, i);
    if (*it_targetList == expr)
    {
      // targetList.set(i, target);
      *it_targetList = expr;
      target->setParent(SharedObject(SQLContainsExpr));
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}
